/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package mS.impl;

import java.util.Collection;

import mH1.MH1;
import mH2.MH2;
import mH3.MH3;
import mS.CPU;
import mS.Data;
import mS.MSPackage;
import mS.Protocol;
import mS.SubTask;
import mS.Task;
import node1.AbstractTask;
import node1.impl.Node1Impl;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.util.EObjectContainmentEList;
import org.eclipse.emf.ecore.util.EObjectContainmentWithInverseEList;
import org.eclipse.emf.ecore.util.InternalEList;

import pUNB.PUNBFactory;
import utils.UtilsModelInstance;
import zFactory.NodeBusyPeriod;
import zFactory.NodeLiu73a01;
import zFactory.NodePUNB;
import zFactory.NodeSrl90a01;
import zFactory.NodeSrl90a02;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>System</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link mS.impl.SystemImpl#getData <em>Data</em>}</li>
 *   <li>{@link mS.impl.SystemImpl#getCpus <em>Cpus</em>}</li>
 *   <li>{@link mS.impl.SystemImpl#getTasks <em>Tasks</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class SystemImpl extends Node1Impl implements mS.System {
	/**
	 * The cached value of the '{@link #getData() <em>Data</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getData()
	 * @generated
	 * @ordered
	 */
	protected EList<Data> data;

	/**
	 * The cached value of the '{@link #getCpus() <em>Cpus</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getCpus()
	 * @generated
	 * @ordered
	 */
	protected EList<CPU> cpus;

	/**
	 * The cached value of the '{@link #getTasks() <em>Tasks</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getTasks()
	 * @generated
	 * @ordered
	 */
	protected EList<Task> tasks;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected SystemImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return MSPackage.Literals.SYSTEM;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<Data> getData() {
		if (data == null) {
			data = new EObjectContainmentEList<Data>(Data.class, this, MSPackage.SYSTEM__DATA);
		}
		return data;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<CPU> getCpus() {
		if (cpus == null) {
			cpus = new EObjectContainmentEList<CPU>(CPU.class, this, MSPackage.SYSTEM__CPUS);
		}
		return cpus;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<Task> getTasks() {
		if (tasks == null) {
			tasks = new EObjectContainmentWithInverseEList<Task>(Task.class, this, MSPackage.SYSTEM__TASKS, MSPackage.TASK__PARENT);
		}
		return tasks;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public NotificationChain eInverseAdd(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
		switch (featureID) {
			case MSPackage.SYSTEM__TASKS:
				return ((InternalEList<InternalEObject>)(InternalEList<?>)getTasks()).basicAdd(otherEnd, msgs);
		}
		return super.eInverseAdd(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
		switch (featureID) {
			case MSPackage.SYSTEM__DATA:
				return ((InternalEList<?>)getData()).basicRemove(otherEnd, msgs);
			case MSPackage.SYSTEM__CPUS:
				return ((InternalEList<?>)getCpus()).basicRemove(otherEnd, msgs);
			case MSPackage.SYSTEM__TASKS:
				return ((InternalEList<?>)getTasks()).basicRemove(otherEnd, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case MSPackage.SYSTEM__DATA:
				return getData();
			case MSPackage.SYSTEM__CPUS:
				return getCpus();
			case MSPackage.SYSTEM__TASKS:
				return getTasks();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case MSPackage.SYSTEM__DATA:
				getData().clear();
				getData().addAll((Collection<? extends Data>)newValue);
				return;
			case MSPackage.SYSTEM__CPUS:
				getCpus().clear();
				getCpus().addAll((Collection<? extends CPU>)newValue);
				return;
			case MSPackage.SYSTEM__TASKS:
				getTasks().clear();
				getTasks().addAll((Collection<? extends Task>)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case MSPackage.SYSTEM__DATA:
				getData().clear();
				return;
			case MSPackage.SYSTEM__CPUS:
				getCpus().clear();
				return;
			case MSPackage.SYSTEM__TASKS:
				getTasks().clear();
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case MSPackage.SYSTEM__DATA:
				return data != null && !data.isEmpty();
			case MSPackage.SYSTEM__CPUS:
				return cpus != null && !cpus.isEmpty();
			case MSPackage.SYSTEM__TASKS:
				return tasks != null && !tasks.isEmpty();
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	public void compute() {

		boolean equalsPeriod = true;
		
		/**/
		EList<Integer> l_period = new BasicEList<Integer> ();
		EList<Integer> l_wcet = new BasicEList<Integer> ();
		EList<Integer> l_deadline = new BasicEList<Integer> ();
		EList<Integer> l_priority = new BasicEList<Integer> ();
		EList<Integer> l_blocking = new BasicEList<Integer>();
		EList<String> l_name = new BasicEList<String> ();

		/***************************************************************
		 * 
		 * Case with no shared resources
		 * 
		 ***************************************************************/
		if (this.data == null)
		{
			/**/
			for (AbstractTask at : this.tasks) {

				Task t = (Task)at;

				/**/
				for (SubTask st : t.getSubTasks()) {

					l_name.add(st.getSubId());
					l_period.add(t.getPeriod());
					l_deadline.add(t.getDeadline());

					if (t.getDeadline() < t.getPeriod()) {

						equalsPeriod = false;
					}

					l_wcet.add(st.getWcet());
					l_priority.add(st.getPriority());
				}

			}

			if (equalsPeriod) 
			{
				/* Create Models with specific assumptions, then add to general List and children list*/
				MH1 lm_1 = (MH1)UtilsModelInstance.createBasicModelType1(this.getCpus().get(0).getPolicy(), l_name, l_wcet, l_period, l_priority);
				UtilsModelInstance.linkComputeBox(this, lm_1, false);
				lm_1.compute();
			}

			/* Create Model type 2, deadline less or equal than period with specific assumptions, then add to general List and children list*/
			MH2 lm_2 = (MH2)UtilsModelInstance.createBasicModelType2( this.getCpus().get(0).getPolicy(), l_name, l_wcet, l_period, l_deadline, l_priority);
			UtilsModelInstance.linkComputeBox(this, lm_2, false);
			lm_2.compute();

		}
		/***************************************************************
		 * 
		 * Case with shared resources
		 * 
		 ***************************************************************/
		else
		{
			/**/
			for (AbstractTask at : this.tasks) 
			{
				Task t = (Task)at;
				int executionTime = 0;
				int priority = 0;

				/**/
				if (t.getDeadline() < t.getPeriod()) {equalsPeriod = false;}
				/**/
				for (SubTask st : t.getSubTasks()) 
				{
					executionTime += st.getWcet();
					priority = st.getPriority();
				}

				l_blocking.add(-1);
				/**/
				if (equalsPeriod) {l_deadline.add(t.getPeriod());}
				else {l_deadline.add(t.getDeadline());}

				l_name.add(t.getId());
//				System.out.println("System, id:" + t.getId());
				l_period.add(t.getPeriod());
				l_priority.add(priority);
				l_wcet.add(executionTime);
			}

			if (equalsPeriod)
			{
				/* Create Models with specific assumptions, then add to general List and children list*/
				MH3 assumptionsModel3 = (MH3)UtilsModelInstance.createMH3(this.getCpus().get(0).getPolicy(), l_wcet, l_period, l_name);
				UtilsModelInstance.linkComputeBox(this, assumptionsModel3, false);
				assumptionsModel3.compute();
			}

			if (this.data.get(0).getPolicy() == Protocol.PIP)
			{
				UtilsModelInstance.setNode(this, new NodeSrl90a01(this.data, this.tasks, true));
			}
			else if (this.data.get(0).getPolicy() == Protocol.PCP)
			{
				UtilsModelInstance.setNode(this, new NodeSrl90a02(this.data, this.tasks, true));
			}
		}
		/***************************************************************
		 * 
		 * Dataflow scheme: compute pertinent values
		 * 
		 ***************************************************************/
		/**/
		EList<AbstractTask> list_tasks = new BasicEList<AbstractTask>();
		for (Task t : this.tasks) 
		{
			int wcet = 0;
			for (SubTask st : t.getSubTasks()){
				wcet += st.getWcet();
			}
			pUNB.Task taskPUNB = PUNBFactory.eINSTANCE.createTask();
			taskPUNB.setWcet(wcet);
			taskPUNB.setPeriod(t.getPeriod());
			list_tasks.add(taskPUNB);
		}
		UtilsModelInstance.setNode(this, new NodePUNB(list_tasks, true));
		
		/**/
		UtilsModelInstance.setNode(this, new NodeLiu73a01(list_tasks.size(), true));
		
		/**/
		UtilsModelInstance.setNode(this, new NodeBusyPeriod(list_tasks, true));
	}
} //SystemImpl
